/*! ******************************************************************************
 *
 * Created on 2022-08-01
 *
 * Copyright(c) YuZhou Big Data Laboratory CO.,Ltd, 2022.  All rights reserved.
 *
 *******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/

package org.yzbdl.lanius.ui.plugin.dialog;

import java.io.File;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import org.apache.commons.lang.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.logging.LogChannel;
import org.pentaho.di.core.logging.LogChannelInterface;
import org.pentaho.di.job.JobMeta;
import org.pentaho.di.trans.ClientVersion;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.ui.core.gui.GUIResource;
import org.pentaho.di.ui.spoon.Spoon;
import org.pentaho.di.ui.spoon.job.JobGraph;
import org.pentaho.di.ui.spoon.trans.TransGraph;
import org.pentaho.di.ui.util.DialogPositionUtil;
import org.pentaho.xul.swt.tab.TabItem;
import org.pentaho.xul.swt.tab.TabSet;
import org.yzbdl.lanius.authorize.verification.LicenseVerification;
import org.yzbdl.lanius.core.constant.LocalDir;
import org.yzbdl.lanius.core.plugins.install.PluginInstaller;
import org.yzbdl.lanius.core.plugins.install.PluginLoader;
import org.yzbdl.lanius.core.plugins.metastore.CategoryI18n;
import org.yzbdl.lanius.core.plugins.metastore.LdrPluginEntity;
import org.yzbdl.lanius.util.LogUtil;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;

/**
 * 插件安装
 *
 * @author tanpeng@yzbdl.ac.cn
 * @version 1.0
 * @date 2022-08-02 11:19
 */
public class PluginInstallDialog extends Dialog {

    protected static final LogChannelInterface LOGGER = new LogChannel("PluginInstallDialog");

    private static final String ZIP = ".zip", EMPTY_VAL = "!!";

    private static final int DEFAULT_THREE = 3;

    private final String VALUE_Y = "是";

    private final Shell parent;

    private Display display = null;

    private Shell shell;

    private static final int STYLE = SWT.DIALOG_TRIM | SWT.RESIZE;

    private final int width, height;

    private final Font titleFont = new Font(null, "微软雅黑", 15, SWT.BOLD);
    private final Font contentFont = new Font(null, "微软雅黑", 12, SWT.NORMAL);

    private Text labelPath;

    /** 基础信息 */
    private Group baseInfoGroup;
    private Label pluginName, pluginId, pluginType, pluginCategory, pluginSize, pluginVersion, pluginDate, pluginAuthor;
    private final String pluginSizeStr = "大小：", pluginVersionStr = "版本号：", pluginDateStr = "版本日期：",
        pluginAuthorStr = "作者：";
    private Label pluginImage;
    private Text pluginDesc;
    private Composite pluginSplashComp;
    private Label pluginMainClassValue;
    private Label pluginI18nValue;
    private Label pluginPointValue;
    private Label pluginCustomClassLoaderValue;

    private Button installBtn;

    /** 默认填充数据 */
    String defaultMainClassValue = "org.lanius.trans.xxxMeta", defaultI18nValue = "org.lanius.trans.xxx",
        defaultPointValue = "org.lanius.trans.xxx";
    String defaultPluginName = "插件名称", defaultPluginId = "插件ID", defaultPluginCategory = "插件类型",
        defaultPluginType = "插件类别", defaultPluginSize = "0MB", defaultPluginVersion = "0.0.1",
        defaultPluginDate = "2022-02-22", defaultPluginAuthor = "插件开发者", defaultPluginDesc = "插件描述",
        defaultImagePath = "ui/images/plugin/default.png";
    Image defaultImage = GUIResource.getInstance().getImage(defaultImagePath, 125, 106);

    /**
     * 创建对话框
     */
    public PluginInstallDialog() {
        super(Spoon.getInstance().getShell(), STYLE);
        this.parent = Spoon.getInstance().getShell();
        setText("插件安装对话框");
        this.width = 880;
        this.height = 1020;
    }

    /**
     * 打开对话框
     */
    public void open() {
        display = parent.getDisplay();
        createContents();
        shell.layout();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    /**
     * 创建对话框内容
     */
    private void createContents() {
        shell = new Shell(parent, STYLE);
        shell.setLayout(new GridLayout());
        shell.setImage(GUIResource.getInstance().getImageShellTitle());
        shell.setBackground(GUIResource.getInstance().getColorWhite());
        shell.setText("安装插件");
        // 设置窗体大小和位置
        DialogPositionUtil.getXyPoint(parent, width, height, shell);

        /* 基本容器 */
        Composite installComp = new Composite(shell, SWT.NONE);
        installComp.setBackground(GUIResource.getInstance().getColorWhite());
        GridData gdInstallComp = new GridData(GridData.FILL_HORIZONTAL);
        gdInstallComp.horizontalAlignment = SWT.CENTER;
        installComp.setLayoutData(gdInstallComp);
        RowLayout installLayout = new RowLayout();
        installLayout.fill = true;
        installLayout.center = true;
        installLayout.marginTop = 40;
        installLayout.marginBottom = 30;
        installLayout.marginWidth = 20;
        installLayout.spacing = 15;
        installComp.setLayout(installLayout);

        // 文本框加容器用于上下对齐
        Composite labelComp = getLabelCenterComp(installComp);
        Label labelText = new Label(labelComp, SWT.NONE);
        labelText.setBackground(GUIResource.getInstance().getColorWhite());
        labelText.setText("本地安装：");

        Composite labelPathComp = getTextCenterComp(installComp);
        labelPath = new Text(labelPathComp, SWT.NONE | SWT.SINGLE);
        labelPath.setBackground(GUIResource.getInstance().getColorWhite());
        labelPath.setLayoutData(new RowData(570, SWT.DEFAULT));
        labelPath.setEditable(false);
        labelPath.setMessage("选择文件");

        Button browserBtn = new Button(installComp, SWT.NONE);
        browserBtn.setLayoutData(new RowData(100, 32));
        browserBtn.setText("浏览文件");
        browserBtn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                FileDialog dialog = new FileDialog(shell, SWT.OPEN);

                List<String> filterExtensions = new ArrayList<>();
                List<String> filterNames = new ArrayList<>();
                filterExtensions.add("*.zip");
                filterNames.add("压缩文件(.zip)");
                dialog.setFilterExtensions(filterExtensions.toArray(new String[0]));
                dialog.setFilterNames(filterNames.toArray(new String[0]));

                if (dialog.open() != null) {
                    String path = dialog.getFilterPath() + System.getProperty("file.separator") + dialog.getFileName();
                    labelPath.setText(path);
                    initPluWithDirOrFile(path);
                }
            }
        });

        pluginBaseInfo();
        pluginDevInfo();
        bottomBtn();
    }

    /**
     * 根据路径读取插件信息
     *
     * @param path zip路径或目录路径
     */
    private void initPluWithDirOrFile(String path) {
        try {
            refreshWithDefault();
            File file = new File(path);
            if (!file.isDirectory() && !file.getAbsolutePath().endsWith(ZIP)) {
                throw new KettleException("目标文件类型不支持");
            }
            // 目标是zip文件
            singleImportPlugin(file);
        } catch (Exception e) {
            e.printStackTrace();
            installBtn.setEnabled(false);
            setMessage("操作失败:" + e.getMessage(), Const.MESSAGE_ERROR);
        }
    }

    /**
     * byte 转为 可视化格式
     * @param size 大小
     * @return 格式化的大小
     */
    public static String readableFileSize(long size) {
        if (size <= 0) {
            return "0B";
        }
        final String[] units = new String[] {"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int)(Math.log10(size) / Math.log10(1024));
        return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
    }

    /**
     * 读取单个插件压缩包信息
     *
     * @param zipFile 目标压缩包
     * @throws Exception 读取失败
     */
    private void singleImportPlugin(File zipFile) throws Exception {
        List<LdrPluginEntity> pluginEntities;
        installBtn.setEnabled(true);
        File pluginTmpFolder = PluginInstaller.unZipPluginToTmpDir(zipFile);
        try {
            pluginEntities = PluginInstaller.extractPluginInfo(pluginTmpFolder.getAbsolutePath());
            if (pluginEntities.size() == 0) {
                setMessage("机器码不匹配", Const.MESSAGE_ERROR);
            }
            if (!LicenseVerification.ACTIVE_ENTERPRISE_EDITION && pluginEntities.get(0).getEnterprise()) {
                setMessage("插件\"" + pluginEntities.get(0).getName() + "\"只能在商业版中安装！", Const.MESSAGE_ERROR);
            }
            if (!pluginEntities.isEmpty()) {
                showData(pluginEntities.get(0), zipFile, pluginTmpFolder);
            }
        } finally {
            FileUtil.del(pluginTmpFolder.getParentFile());
        }
    }

    /**
     * 根据注解全路径名获取类型名 eq: org.yzbdl.XXX ==> XXX
     *
     * @param fullName 全路径名
     * @return 类型名
     */
    private String getShortPluginTypeName(String fullName) {
        String[] split = fullName.split("\\.");
        return split[split.length - 1];
    }

    /**
     * 空处理
     * @param source 源
     * @return 处理后的值
     */
    private String notNull(String source) {
        return Optional.ofNullable(source).orElse("");
    }

    /**
     * 展示数据
     * @param entity 实体
     * @param sourceZip 源文件
     * @param targetTmpZip 目标文件
     */
    private void showData(LdrPluginEntity entity, File sourceZip, File targetTmpZip) {
        // 基本信息
        // 第一行
        int pluginNameWidth = getTextWith(notNull(entity.getName()), titleFont);
        pluginName.setText(notNull(entity.getName()));
        pluginName.setBounds(160, 20, pluginNameWidth, 36);
        pluginId.setText(notNull(entity.getPluginId()));
        pluginId.setBounds(180 + pluginNameWidth, 32, 200, 25);
        // 第二行
        String shortPluginTypeI18n = getShortPluginTypeName(notNull(entity.getPluginTypeName()));
        String shortPluginType = CategoryI18n.fromStringOrNull(shortPluginTypeI18n).getI18n();
        pluginCategory.setText(shortPluginType);
        int pluginTypeWidth = getTextWith(shortPluginType, contentFont);
        pluginCategory.setBounds(160, 80, pluginTypeWidth, 25);
        String pluginTypeStr = notNull(entity.getCategory());
        pluginType.setVisible(false);
        if (StringUtils.isNotBlank(pluginTypeStr) && !EMPTY_VAL.equals(pluginTypeStr)) {
            pluginType.setVisible(true);
            pluginType.setText(pluginTypeStr);
            pluginType.setBounds(172 + pluginTypeWidth, 80, getTextWith(pluginTypeStr, contentFont), 25);
        }
        // 第二行 右侧
        pluginSize.setText(pluginSizeStr + readableFileSize(sourceZip.length()));
        pluginVersion.setText(pluginVersionStr + notNull(entity.getVersion()));
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        pluginDate.setText(pluginDateStr + simpleDateFormat.format(FileUtil.lastModifiedTime(sourceZip)));
        pluginDesc.setText(notNull(entity.getProfile()));
        // 插件LOGO图片
        // 从外面的icons目录读取图片
        File[] ls = FileUtil.ls(targetTmpZip.getAbsolutePath() + File.separator + LocalDir.PLUGIN_ICONS_DIR);
        Optional<File> max = Arrays.stream(ls).max(File::compareTo);
        if (max.isPresent()) {
            try {
                ImageData imageData = new ImageData(max.get().toURI().toURL().openStream());
                Image img = new Image(display, imageData.scaledTo(120, 120));
                pluginImage.setImage(img);
            } catch (Exception e) {
                LOGGER.logError("插件图标加载失败！", e);
                //
            }
        }
        // 插件介绍图 从外面的screenShotsList目录读取介绍图片
        if (new File(targetTmpZip.getAbsolutePath() + File.separator + LocalDir.PLUGIN_SCREENSHOTS_DIR).exists()) {
            File[] screenShotsList =
                FileUtil.ls(targetTmpZip.getAbsolutePath() + File.separator + LocalDir.PLUGIN_SCREENSHOTS_DIR);
            pluginSplashComp.dispose();
            showPluginSplash(screenShotsList);
        }
        // 开发信息
        pluginMainClassValue.setText(notNull(entity.getMainClassName()));
        pluginI18nValue.setText(notNull(entity.getI18nPackageName()));
        pluginPointValue.setText(notNull(entity.getPluginTypeName()));

        String valueN = "否";
        pluginCustomClassLoaderValue.setText(entity.getClSeparateClassLoaderNeeded() ? VALUE_Y : valueN);
    }

    /**
     * 设置提示信息
     *
     * @param msg 提示信息
     */
    private void setMessage(String msg, String msgType) {
        showMessage(msg, msgType, shell);
    }

    /**
     * 显示消息
     * @param msg  消息内容
     * @param msgType  消息类型
     * @param shell  面板
     */
    static void showMessage(String msg, String msgType, Shell shell) {
        msg = msg.replaceAll("\\n", "");
        msg = msg.replaceAll("\\r", "");
        MessageBox dialog = new MessageBox(shell, SWT.OK | (msgType.equals(Const.MESSAGE_SUCCESS) ? SWT.ICON_INFORMATION
            : (msgType.equals(Const.MESSAGE_WARNING) ? SWT.ICON_WARNING : SWT.ICON_ERROR)));
        dialog.setText("提示信息");
        dialog.setMessage(msg);
        dialog.open();
    }

    /**
     * 初始化数据展示区
     */
    public void refreshWithDefault() {
        // 基本信息
        pluginName.setText(defaultPluginName);
        pluginName.setBounds(160, 20, getTextWith(defaultPluginName, titleFont), 36);
        pluginImage.setImage(defaultImage);
        pluginId.setText(defaultPluginId);
        pluginCategory.setText(defaultPluginCategory);
        pluginType.setText(defaultPluginType);
        pluginSize.setText(pluginSizeStr + defaultPluginSize);
        pluginVersion.setText(pluginVersionStr + defaultPluginVersion);
        pluginDate.setText(pluginDateStr + defaultPluginDate);
        pluginAuthor.setText(pluginAuthorStr + defaultPluginAuthor);
        pluginDesc.setText(defaultPluginDesc);
        pluginSplashComp.dispose();
        showPluginSplash(new File[0]);
        // 开发信息
        pluginMainClassValue.setText(defaultMainClassValue);
        pluginI18nValue.setText(defaultI18nValue);
        pluginPointValue.setText(defaultPointValue);
        pluginCustomClassLoaderValue.setText(VALUE_Y);
        // 按钮控制
        installBtn.setEnabled(false);
    }

    /**
     * 插件基础信息
     */
    private void pluginBaseInfo() {
        Composite pluginComp = getRowLayoutComposite(10);

        baseInfoGroup = new Group(pluginComp, SWT.NONE);
        baseInfoGroup.setBackground(GUIResource.getInstance().getColorWhite());
        baseInfoGroup.setLayoutData(new RowData(812, SWT.DEFAULT));
        baseInfoGroup.setText("基本信息");
        RowLayout baseInfoGroupLayout = new RowLayout();
        baseInfoGroup.setLayout(baseInfoGroupLayout);

        Composite pluginInfoComp = new Composite(baseInfoGroup, SWT.NONE);
        pluginInfoComp.setLayoutData(new RowData(800, 300));
        pluginInfoComp.setBackground(GUIResource.getInstance().getColorWhite());

        pluginImage = new Label(pluginInfoComp, SWT.SHADOW_IN | SWT.CENTER);
        pluginImage.setBackground(GUIResource.getInstance().getColorWhite());
        pluginImage.setImage(defaultImage);
        pluginImage.setBounds(20, 20, 132, 132);

        pluginName = new Label(pluginInfoComp, SWT.NONE);
        pluginName.setBackground(GUIResource.getInstance().getColorWhite());
        pluginName.setFont(titleFont);
        pluginName.setText(defaultPluginName);
        pluginName.setBounds(160, 20, getTextWith(defaultPluginName, titleFont), 36);

        pluginId = new Label(pluginInfoComp, SWT.NONE);
        pluginId.setBackground(GUIResource.getInstance().getColorWhite());
        pluginId.setBounds(280, 32, 200, 25);
        pluginId.setText(defaultPluginId);

        pluginCategory = new Label(pluginInfoComp, SWT.CENTER);
        pluginCategory.setBackground(GUIResource.getInstance().getColor(233, 233, 188));
        pluginCategory.setBounds(160, 80, 80, 25);
        pluginCategory.setText(defaultPluginCategory);

        pluginType = new Label(pluginInfoComp, SWT.CENTER);
        pluginType.setBackground(GUIResource.getInstance().getColor(200, 233, 233));
        pluginType.setBounds(270, 80, 80, 25);
        pluginType.setText(defaultPluginType);

        pluginSize = new Label(pluginInfoComp, SWT.NONE);
        pluginSize.setBackground(GUIResource.getInstance().getColorWhite());
        pluginSize.setBounds(160, 130, 120, 24);
        pluginSize.setText(pluginSizeStr + defaultPluginSize);

        pluginVersion = new Label(pluginInfoComp, SWT.NONE);
        pluginVersion.setBackground(GUIResource.getInstance().getColorWhite());
        pluginVersion.setText(pluginVersionStr + defaultPluginVersion);
        pluginVersion.setBounds(275, 130, 120, 24);

        pluginDate = new Label(pluginInfoComp, SWT.NONE);
        pluginDate.setBackground(GUIResource.getInstance().getColorWhite());
        pluginDate.setText(pluginDateStr + defaultPluginDate);
        pluginDate.setBounds(420, 130, 190, 24);

        pluginAuthor = new Label(pluginInfoComp, SWT.NONE);
        pluginAuthor.setBackground(GUIResource.getInstance().getColorWhite());
        pluginAuthor.setText(pluginAuthorStr + defaultPluginAuthor);
        pluginAuthor.setBounds(640, 130, 180, 24);

        pluginDesc = new Text(pluginInfoComp, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL);
        pluginDesc.setBackground(GUIResource.getInstance().getColorWhite());
        pluginDesc.setEditable(false);
        pluginDesc.setText(defaultPluginDesc);
        pluginDesc.setBounds(20, 180, 765, 100);

        showPluginSplash(new File[0]);

    }

    /**
     * 初始化一个指定配置的面板
     * @param marginWidth 指定宽
     * @return 返回面板
     */
    private Composite getRowLayoutComposite(int marginWidth) {
        Composite composite = new Composite(shell, SWT.NONE);
        composite.setBackground(GUIResource.getInstance().getColorWhite());
        GridData gdComposite = new GridData(GridData.FILL_HORIZONTAL);
        gdComposite.horizontalAlignment = SWT.LEFT;
        composite.setLayoutData(gdComposite);
        RowLayout compositeLayout = new RowLayout();
        compositeLayout.marginTop = 10;
        compositeLayout.marginBottom = 10;
        compositeLayout.marginWidth = marginWidth;
        composite.setLayout(compositeLayout);
        return composite;
    }

    /**
     * 获取文本宽度
     * @param words 文本
     * @param font 字体
     * @return 宽度
     */
    private int getTextWith(String words, Font font) {
        Label text = new Label(shell, SWT.NONE);
        text.setText(words);
        text.setFont(font);
        int width = text.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
        text.dispose();
        return width;
    }

    /**
     * 插件介绍图
     * @param files 文件列表
     */
    private void showPluginSplash(File[] files) {
        pluginSplashComp = new Composite(baseInfoGroup, SWT.NONE);
        pluginSplashComp.setBackground(GUIResource.getInstance().getColorWhite());
        // 注意点，顶层容器FillLayout且必须有尺寸且小于滚动条容器尺寸
        pluginSplashComp.setLayoutData(new RowData(805, 240));
        FillLayout flPluginSplashComp = new FillLayout();
        flPluginSplashComp.marginWidth = 20;
        flPluginSplashComp.marginHeight = 10;
        flPluginSplashComp.spacing = 10;
        pluginSplashComp.setLayout(flPluginSplashComp);

        ScrolledComposite scrolledComposite =
            new ScrolledComposite(pluginSplashComp, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
        scrolledComposite.setLayout(new FillLayout());
        scrolledComposite.setBackground(GUIResource.getInstance().getColorWhite());
        scrolledComposite.setExpandHorizontal(true);
        scrolledComposite.setExpandVertical(true);

        Composite pluginSplashCompIn = new Composite(scrolledComposite, SWT.NONE);
        pluginSplashCompIn.setBackground(GUIResource.getInstance().getColorWhite());

        int margeRight = 245;
        int dataSize = 0;
        try {
            if (ObjectUtil.isNotEmpty(files)) {
                dataSize = files.length;
                for (int i = 0; i < files.length; i++) {
                    ImageData imageData = new ImageData(files[i].toURI().toURL().openStream());
                    Image img = new Image(display, imageData.scaledTo(210, 130));
                    Label splash = new Label(pluginSplashCompIn, SWT.SHADOW_IN | SWT.CENTER);
                    splash.setBackground(GUIResource.getInstance().getColorWhite());
                    splash.setImage(img);
                    splash.setBounds(24 + margeRight * i, 26, 220, 140);
                }
            } else {
                for (int i = 0; i < DEFAULT_THREE; i++) {
                    Label splash = new Label(pluginSplashCompIn, SWT.SHADOW_IN | SWT.CENTER);
                    splash.setImage(defaultImage);
                    splash.setBackground(GUIResource.getInstance().getColorWhite());
                    splash.setBounds(24 + margeRight * i, 26, 220, 140);
                    dataSize = i;
                }
            }
        } catch (Exception e) {
            LOGGER.logError("介绍图加载失败！", e);
            //
        }
        scrolledComposite.setContent(pluginSplashCompIn);
        scrolledComposite.setMinSize(margeRight * dataSize + 24, 180);
        baseInfoGroup.layout();
        pluginSplashComp.layout();
    }

    /**
     * 底部按钮
     */
    private void bottomBtn() {
        Composite toolComp = new Composite(shell, SWT.NONE);
        toolComp.setBackground(GUIResource.getInstance().getColorWhite());
        GridData gdToolComp = new GridData(GridData.FILL_HORIZONTAL);
        gdToolComp.horizontalAlignment = SWT.RIGHT;
        toolComp.setLayoutData(gdToolComp);
        RowLayout toolLayout = new RowLayout();
        toolLayout.marginTop = 10;
        toolLayout.marginBottom = 10;
        toolLayout.marginWidth = 15;
        toolLayout.spacing = 15;
        toolComp.setLayout(toolLayout);

        installBtn = new Button(toolComp, SWT.NONE);
        installBtn.setLayoutData(new RowData(90, 32));
        installBtn.setText("安装");
        installBtn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                try {
                    LdrPluginEntity ldrPluginEntity = PluginInstaller.importFromZip(new File(labelPath.getText()));
                    PluginLoader.loadOne(ldrPluginEntity);
                    setMessage("安装成功", Const.MESSAGE_SUCCESS);
                    refreshOpenTab();
                } catch (Exception e1) {
                    setMessage("安装失败:" + e1.getMessage(), Const.MESSAGE_ERROR);
                    LOGGER.logError("安装失败:" + e1);
                }
            }
        });

        /* 底部按钮 */
        Button closeBtn = new Button(toolComp, SWT.NONE);
        closeBtn.setLayoutData(new RowData(90, 32));
        closeBtn.setText("关闭");
        closeBtn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                dispose();
            }
        });
    }

    /**
     * 刷新打开的转换
     */
    public static void refreshOpenTab() {
        try {
            TabSet tabSet = Spoon.getInstance().getTabSet();
            TabItem activeItem = tabSet.getSelected();
            List<TabItem> allTabItem = tabSet.getAllTab();
//            boolean isFromRepository = Spoon.getInstance().getRepository() != null;
            // 优化在打开资源库里转换离线安装缺失插件完成之后转换显示问题(之前处理的是本地转换文件问题)
            Display.getDefault().syncExec(() -> {
                for (TabItem tab : allTabItem) {
                    Object tabObj = tab.getControl();
                    reloadOpenTabGraph(tabObj);
                }
            });
            Spoon.getInstance().refreshGraph();
            Spoon.getInstance().refreshDesignTree();
            tabSet.setSelected(activeItem);
        } catch (Exception e0) {
            // ignore
        }
    }

    /**
     * 获取上文本下居中的面板
     * @param parentComp 上一层
     * @return 面板
     */
    public static Composite getLabelCenterComp(Composite parentComp) {
        Composite composite = new Composite(parentComp, SWT.NONE);
        composite.setBackground(GUIResource.getInstance().getColorWhite());
        RowLayout rlComposite = new RowLayout(SWT.VERTICAL);
        rlComposite.marginLeft = 0;
        rlComposite.justify = true;
        composite.setLayout(rlComposite);
        return composite;
    }

    /**
     * 创建一个文本居中面板
     * @param parentComp 上一层
     * @return 面板
     */
    public static Composite getTextCenterComp(Composite parentComp) {
        Composite labelCenterComp = new Composite(parentComp, SWT.BORDER);
        labelCenterComp.setBackground(GUIResource.getInstance().getColorWhite());
        RowLayout rlLabelCenterComp = new RowLayout(SWT.VERTICAL);
        rlLabelCenterComp.marginWidth = 4;
        rlLabelCenterComp.marginTop = 4;
        labelCenterComp.setLayout(rlLabelCenterComp);
        return labelCenterComp;
    }

    /**
     * 刷新打开的图像界面
     * @param graphObject 画布对象
     */
    public static void reloadOpenTabGraph(Object graphObject) {
        if (graphObject instanceof TransGraph) {
            reloadTransGraph(((TransGraph)graphObject));
        } else if (graphObject instanceof JobGraph) {
            reloadJobGraph(((JobGraph)graphObject));
        }

    }

    /**
     * 刷新转换
     * @param transGraph 转换元数据
     */
    public static void reloadTransGraph(TransGraph transGraph) {
        try {
            TransMeta thisTransMeta = transGraph.getTransMeta();
            TransMeta reloadTransMeta;
            boolean isFromRepository = thisTransMeta.getRepository() != null && thisTransMeta.getObjectId() != null;
            if (isFromRepository) {
                try {
                    reloadTransMeta =
                        Spoon.getInstance().getRepository().loadTransformation(thisTransMeta.getObjectId(), null);
                } catch (KettleException e) {
                    LOGGER.logError("无法从资源库读取转换！\r\n{}", e);
                    return;
                }
            } else {
                reloadTransMeta = new TransMeta(thisTransMeta.getFilename());
            }
            if (reloadTransMeta != null) {
                reloadTransMeta.clearChanged();
                ClientVersion clientVersion = new ClientVersion();
                clientVersion.setClient(ClientVersion.LANIUS);
                reloadTransMeta.setClientVersion(clientVersion);
                reloadTransMeta.setRepository(thisTransMeta.getRepository());
                // 更新画布中的转换文件
                transGraph.setTransMeta(reloadTransMeta);
                Spoon.getInstance().saveFileWhenDownLoadUpdate(reloadTransMeta);
                if (!isFromRepository) {
                    Spoon.getInstance().openFile(reloadTransMeta.getFilename(), false);
                }
            }
        } catch (KettleException e) {
            LogUtil.warn("{},重新加载转换失败", e.getMessage());
        }
    }

    /**
     * 刷新转换
     * @param jobGraph 作业元数据
     */
    public static void reloadJobGraph(JobGraph jobGraph) {
        try {
            JobMeta thisJobMeta = jobGraph.getJobMeta();
            JobMeta reloadJobMeta;
            boolean isFromRepository = thisJobMeta.getRepositoryDirectory() != null && thisJobMeta.getObjectId() != null;
            if (isFromRepository) {
                try {
                    reloadJobMeta = Spoon.getInstance().getRepository().loadJob(thisJobMeta.getObjectId(), null);
                } catch (KettleException e) {
                    LOGGER.logError("无法从资源库读取作业！\r\n{}", e);
                    return;
                }
            } else {
                reloadJobMeta = new JobMeta(thisJobMeta.getFilename(), null);
            }
            if (reloadJobMeta != null) {
                reloadJobMeta.clearChanged();
                ClientVersion clientVersion = new ClientVersion();
                clientVersion.setClient(ClientVersion.LANIUS);
                reloadJobMeta.setClientVersion(clientVersion);
                reloadJobMeta.setRepository(reloadJobMeta.getRepository());
                jobGraph.setJobMeta(reloadJobMeta);
                Spoon.getInstance().saveFileWhenDownLoadUpdate(reloadJobMeta);
                if (!isFromRepository) {
                    Spoon.getInstance().openFile(reloadJobMeta.getFilename(), false);
                }
            }
        } catch (KettleException e) {
            LogUtil.warn("{},重新加载作业失败", e.getMessage());
        }
    }

    /**
     * 插件开发信息
     */
    private void pluginDevInfo() {
        Composite devComp = getRowLayoutComposite(12);

        /* 开发信息 */
        Group devInfoGroup = new Group(devComp, SWT.NONE);
        devInfoGroup.setBackground(GUIResource.getInstance().getColorWhite());
        devInfoGroup.setLayoutData(new RowData(812, 150));
        devInfoGroup.setText("开发信息");

        Label pluginMainClass = new Label(devInfoGroup, SWT.NONE);
        pluginMainClass.setBackground(GUIResource.getInstance().getColorWhite());
        pluginMainClass.setBounds(32, 41, 90, 24);
        pluginMainClass.setText("插件主类：");

        pluginMainClassValue = new Label(devInfoGroup, SWT.NONE);
        pluginMainClassValue.setBackground(GUIResource.getInstance().getColorWhite());
        pluginMainClassValue.setText(defaultMainClassValue);
        pluginMainClassValue.setBounds(130, 41, 500, 24);

        Label pluginI18n = new Label(devInfoGroup, SWT.NONE);
        pluginI18n.setBackground(GUIResource.getInstance().getColorWhite());
        pluginI18n.setText(" 国 际 化：");
        pluginI18n.setBounds(34, 71, 90, 24);

        pluginI18nValue = new Label(devInfoGroup, SWT.NONE);
        pluginI18nValue.setBackground(GUIResource.getInstance().getColorWhite());
        pluginI18nValue.setText(defaultI18nValue);
        pluginI18nValue.setBounds(130, 71, 500, 24);

        Label pluginPoint = new Label(devInfoGroup, SWT.NONE);
        pluginPoint.setBackground(GUIResource.getInstance().getColorWhite());
        pluginPoint.setText(" 扩 展 点：");
        pluginPoint.setBounds(34, 101, 90, 24);

        pluginPointValue = new Label(devInfoGroup, SWT.NONE);
        pluginPointValue.setBackground(GUIResource.getInstance().getColorWhite());
        pluginPointValue.setText(defaultPointValue);
        pluginPointValue.setBounds(130, 101, 500, 24);

        Label pluginCustomClassLoader = new Label(devInfoGroup, SWT.NONE);
        pluginCustomClassLoader.setBackground(GUIResource.getInstance().getColorWhite());
        pluginCustomClassLoader.setText("独立加载：");
        pluginCustomClassLoader.setBounds(32, 131, 90, 24);

        pluginCustomClassLoaderValue = new Label(devInfoGroup, SWT.NONE);
        pluginCustomClassLoaderValue.setBackground(GUIResource.getInstance().getColorWhite());
        pluginCustomClassLoaderValue.setText(VALUE_Y);
        pluginCustomClassLoaderValue.setBounds(130, 131, 500, 24);
    }

    /**
     * 关闭对话框
     */
    public void dispose() {
        shell.dispose();
    }

    /**
     * 判断对话框是否关闭
     */
    public boolean isDisposed() {
        return this.shell.isDisposed();
    }
}
